package route

import (
	"fmt"
	"gitee.com/gitee-go/core"
	"gitee.com/gitee-go/core/bean/httpBean"
	"gitee.com/gitee-go/core/bean/oauthBean"
	"gitee.com/gitee-go/core/bean/sysBean"
	"gitee.com/gitee-go/core/common"
	"gitee.com/gitee-go/server/comm"
	"gitee.com/gitee-go/server/engine"
	"gitee.com/gitee-go/server/service"
	"gitee.com/gitee-go/utils"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"net/url"
	"time"
)

type OAuthController struct{}

func (OAuthController) GetPath() string {
	return "/api/login/oauth"
}
func (c *OAuthController) Routes(g gin.IRoutes) {
	g.POST("/url", c.authUrl)
	g.POST("/url/:nm", c.authUrlnm)
	g.GET("/back/:nm", c.back)
	g.POST("/token", utils.GinReqParseJson(c.token))
}
func (cs *OAuthController) authUrl(c *gin.Context) {
	//nm := c.Param("nm")
	par := &oauthBean.ParamOAuth{}
	err := service.GetsParam(oauthBean.ParamOAuthKey, par)
	if err != nil {
		core.NewUIRes(common.UICodeErrs).
			SetMsgObjs(err).
			ResJson(c)
		return
	}
	nm, oapp := par.DefAppInfo()
	if nm == "" || oapp == nil || oapp.ClientId == "" || oapp.ClientSecret == "" {
		core.NewUIRes(common.UICodeLoginNoSetOAauth).
			ResJson(c)
		return
	}
	cs.authUrls(c, nm, oapp)
}
func (cs *OAuthController) authUrlnm(c *gin.Context) {
	nm := c.Param("nm")
	par := &oauthBean.ParamOAuth{}
	err := service.GetsParam(oauthBean.ParamOAuthKey, par)
	if err != nil {
		core.NewUIRes(common.UICodeErrs).
			SetMsgObjs(err).
			ResJson(c)
		return
	}
	oapp, ok := par.AppInfo(nm)
	if !ok || oapp.ClientId == "" || oapp.ClientSecret == "" {
		core.NewUIRes(common.UICodeLoginNoSetOAauth).
			ResJson(c)
		return
	}
	cs.authUrls(c, nm, oapp)
}
func (OAuthController) authUrls(c *gin.Context, nm string, oapp *oauthBean.AppInfo) {
	if comm.MainCfg.ServerConf.Host == "" {
		core.NewUIRes(common.UICodeErrs).
			SetMsgObjs("未设置域名").
			ResJson(c)
		return
	}
	switch nm {
	case common.SourceGitee:
		rtul := fmt.Sprintf("%s/api/login/oauth/back/%s", comm.MainCfg.ServerConf.Host, nm)
		ul := fmt.Sprintf("https://gitee.com/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code&scope=%s",
			oapp.ClientId, url.QueryEscape(rtul), "user_info%20projects")
		core.NewUIResOk(&oauthBean.AuthUrlRes{Url: ul}).
			ResJson(c)
	default:
		core.NewUIRes(common.UICodeErrParam).
			ResJson(c)
	}
}
func (OAuthController) errUrl(hs, code string) string {
	return fmt.Sprintf("%s/403?code=%s", hs, code)
}
func (cs *OAuthController) back(c *gin.Context) {
	nm := c.Param("nm")
	code := c.Query("code")
	hs := comm.MainCfg.ServerConf.Host
	sysp := &sysBean.ParamSys{}
	err := service.GetsParam(sysBean.ParamSysKey, sysp)
	if err == nil && sysp.UIWebHost != "" {
		hs = sysp.UIWebHost
	}
	if code == "" {
		//httpex.ResMsgUrl(c, "授权失败-参数错误:"+errds)
		c.Redirect(302, cs.errUrl(hs, "授权失败"))
		return
	}
	par := &oauthBean.ParamOAuth{}
	err = service.GetsParam(oauthBean.ParamOAuthKey, par)
	oapp, ok := par.AppInfo(nm)
	if err != nil || !ok {
		//httpex.ResMsgUrl(c, "授权失败-数据源配置错误")
		c.Redirect(302, cs.errUrl(hs, "source"))
		return
	}

	switch nm {
	case common.SourceGitee:
		cs.backGitee(c, hs, code, nm, oapp)
	default:
		c.Redirect(302, cs.errUrl(hs, "param"))
	}
}
func (OAuthController) token(c *gin.Context, m *struct {
	Code string `json:"code"`
}) {
	if m.Code == "" {
		core.NewUIRes(common.UICodeErrParam).
			ResJson(c)
		return
	}

	mp := utils.Map{}
	key := "oauth-code:" + m.Code
	err := comm.CacheGets(key, &mp)
	if err != nil {
		core.NewUIRes(common.UICodeErr).
			SetMsgf("code not exist").
			ResJson(c)
		return
	}
	comm.CacheSet(key, nil)
	uid, err := mp.GetInt("uid")
	if err != nil {
		core.NewUIRes(common.UICodeErr).
			SetMsgf("uid err").
			ResJson(c)
		return
	}
	usr, ok := service.GetUser(uid)
	if !ok {
		core.NewUIRes(common.UICodeErr).
			SetMsgf("not found user").
			ResJson(c)
		return
	}
	lkey := comm.MainCfg.ServerConf.LoginKey
	if lkey == "" {
		core.NewUIRes(common.UICodeErrs).
			SetMsgObjs("未设置login-key").
			ResJson(c)
		return
	}
	token, err := utils.CreateToken(jwt.MapClaims{
		"uid": fmt.Sprintf("%d", usr.Id),
	}, lkey, time.Hour*24*5)
	if err != nil {
		core.NewUIRes(common.UICodeErrs).
			SetMsgObjs(err).
			ResJson(c)
		return
	}
	if mp.GetBool("isnew") {
		//service.RefreshReposByUid(usr.Id)
		engine.Mgr().GetRefreshEgn().WaitUid(usr.Id)
	}
	core.NewUIResOk(&httpBean.LoginRes{
		Token:         token,
		Id:            fmt.Sprintf("%d", usr.Id),
		Name:          usr.Name,
		Nick:          usr.Nick,
		Avatar:        usr.Avatar,
		LastLoginTime: usr.LoginTime.Format(common.TimeFmt),
	}).ResJson(c)
}
